/**
 *  Copyright (c) 2017-2022 Rushang Co.Ltd All Rights Reserved.
 */
package com.rshang.rsdp.config;

import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;

import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.DispatcherType;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.crypto.hash.Hash;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;

import com.rshang.rsdp.util.shiro.RsdpShiroRealm;

/**
 * 功能简介：shiro配置类<br/>
 * @author zhangjun
 * @create 2017年7月28日下午4:30:59
 * 
 */
@Configuration
public class RsdpShiroConfig {
	
	@Value("${shiro.hashIterations}")
	int hashIterations;
	@Value("${shiro.HashAlgorithmName}")
	String hashAlgorithmName;

	@Bean
	public RsdpShiroRealm createRealm(@Qualifier("md5Macher") HashedCredentialsMatcher md5Macher){
		RsdpShiroRealm myRealm = new RsdpShiroRealm();
		myRealm.setCredentialsMatcher(md5Macher);
		return myRealm;
	}
	
	@Bean
	public EhCacheManager createEhCacheManager(@Autowired EhCacheManagerFactoryBean factoryBean){
		EhCacheManager ehCacheManager = new EhCacheManager();
		ehCacheManager.setCacheManager(factoryBean.getObject());
		//ehCacheManager.setCacheManagerConfigFile("classpath:ehcache.xml");
		return ehCacheManager;
	}
	
	@Bean
	public SecurityManager createSecurityManager(@Autowired RsdpShiroRealm rsdpRealm,@Autowired EhCacheManager cacheManager,@Qualifier("md5Macher") HashedCredentialsMatcher md5Macher){
		DefaultWebSecurityManager sm = new DefaultWebSecurityManager();
		sm.setRealm(rsdpRealm);
		sm.setCacheManager(cacheManager);
		return sm;
	}
	@Bean
	public FilterRegistrationBean delegatingFilterProxy(){
	    FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
	    DelegatingFilterProxy proxy = new DelegatingFilterProxy();
	    proxy.setTargetFilterLifecycle(true);
	    proxy.setTargetBeanName("shiroFilter");
	    filterRegistrationBean.setFilter(proxy);
	    filterRegistrationBean.setDispatcherTypes(DispatcherType.ASYNC, DispatcherType.ERROR, DispatcherType.FORWARD, DispatcherType.INCLUDE,DispatcherType.REQUEST);
	    return filterRegistrationBean;
	}

	@Bean("shiroFilter")
	public ShiroFilterFactoryBean createShiroFilter(@Autowired SecurityManager securityManager){
		ShiroFilterFactoryBean sffb = new ShiroFilterFactoryBean();
		sffb.setSecurityManager(securityManager);
		//拦截器.
		Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
		// 配置不会被拦截的链接 顺序判断
		filterChainDefinitionMap.put("/common/**", "anon");
		filterChainDefinitionMap.put("/kaptcha", "anon");
		filterChainDefinitionMap.put("/images/**", "anon");
		filterChainDefinitionMap.put("/login", "anon");
		filterChainDefinitionMap.put("/", "anon");
		//配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了
		filterChainDefinitionMap.put("/logout", "anon");
		//<!-- 过滤链定义，从上向下顺序执行，一般将/**放在最为下边 -->:这是一个坑呢，一不小心代码就不好使了;
		//<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
		filterChainDefinitionMap.put("/**", "authc");
		// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
		sffb.setLoginUrl("/");
		// 登录成功后要跳转的链接
		sffb.setSuccessUrl("/main");

		//未授权界面;
		sffb.setUnauthorizedUrl("/403");
		sffb.setFilterChainDefinitionMap(filterChainDefinitionMap);
		return sffb;
	}
	
	/**
	 * 凭证匹配器
	 * （由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了）
	 * @return
	 */
	@Bean("md5Macher")
	public HashedCredentialsMatcher hashedCredentialsMatcher(){
		HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
		hashedCredentialsMatcher.setHashAlgorithmName(hashAlgorithmName);//散列算法:这里使用MD5算法;
		hashedCredentialsMatcher.setHashIterations(hashIterations);//散列的次数，比如散列两次，相当于 md5(md5(""));
		return hashedCredentialsMatcher;
	}
	
	/**
	 *  开启shiro aop注解支持.
	 *  使用代理方式;所以需要开启代码支持;
	 * @param securityManager
	 * @return
	 */
	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Autowired SecurityManager securityManager){
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
		return authorizationAttributeSourceAdvisor;
	}
}
